En dybdegående udforskning af Cross-Origin Resource Sharing (CORS) og preflight-requests. Lær hvordan du håndterer CORS-problemer og sikrer dine webapplikationer for et globalt publikum.
Afmystificering af CORS: En dybdegående gennemgang af håndtering af JavaScript Preflight-requests
I den stadigt voksende verden af webudvikling er sikkerhed altafgørende. Cross-Origin Resource Sharing (CORS) er en afgørende sikkerhedsmekanisme implementeret af webbrowsere for at begrænse websider i at foretage anmodninger til et andet domæne end det, der leverede websiden. Dette er en fundamental sikkerhedsfunktion designet til at forhindre ondsindede websteder i at få adgang til følsomme data. Denne omfattende guide vil dykke ned i finesserne ved CORS med specifikt fokus på håndtering af preflight-requests. Vi vil udforske 'hvorfor', 'hvad' og 'hvordan' med CORS og give praktiske eksempler og løsninger på almindelige problemer, som udviklere over hele verden støder på.
Forståelse af Same-Origin Policy
Kernen i CORS er Same-Origin Policy (SOP). Denne politik er en sikkerhedsmekanisme på browserniveau, der begrænser scripts, der kører på én oprindelse, i at få adgang til ressourcer fra en anden oprindelse. En oprindelse er defineret af protokollen (f.eks. HTTP eller HTTPS), domænet (f.eks. example.com) og porten (f.eks. 80 eller 443). To URL'er har samme oprindelse, hvis disse tre komponenter matcher præcist.
For eksempel:
https://www.example.com/app1/index.htmloghttps://www.example.com/app2/index.htmlhar samme oprindelse (samme protokol, domæne og port).https://www.example.com/index.htmloghttp://www.example.com/index.htmlhar forskellige oprindelser (forskellige protokoller).https://www.example.com/index.htmloghttps://api.example.com/index.htmlhar forskellige oprindelser (forskellige underdomæner betragtes som forskellige domæner).https://www.example.com:8080/index.htmloghttps://www.example.com/index.htmlhar forskellige oprindelser (forskellige porte).
SOP er designet til at forhindre ondsindede scripts på ét websted i at få adgang til følsomme data, såsom cookies eller brugerautentificeringsoplysninger, på et andet websted. Selvom den er afgørende for sikkerheden, kan SOP også være restriktiv, især når legitime anmodninger på tværs af oprindelser er nødvendige.
Hvad er Cross-Origin Resource Sharing (CORS)?
CORS er en mekanisme, der giver servere mulighed for at specificere, hvilke oprindelser (domæner, skemaer eller porte) der har tilladelse til at få adgang til deres ressourcer. Den lemper i bund og grund SOP og tillader kontrolleret adgang på tværs af oprindelser. CORS implementeres ved hjælp af HTTP-headere, der udveksles mellem klienten (typisk en webbrowser) og serveren.
Når en browser foretager en anmodning på tværs af oprindelser (dvs. en anmodning til en anden oprindelse end den nuværende side), tjekker den først, om serveren tillader anmodningen. Dette gøres ved at undersøge Access-Control-Allow-Origin-headeren i serverens svar. Hvis oprindelsen af anmodningen er angivet i denne header (eller hvis headeren er sat til *, hvilket tillader alle oprindelser), tillader browseren anmodningen at fortsætte. Ellers blokerer browseren anmodningen og forhindrer JavaScript-koden i at få adgang til svardataene.
Rollen af Preflight-requests
For visse typer anmodninger på tværs af oprindelser igangsætter browseren en preflight-request. Dette er en OPTIONS-anmodning, der sendes til serveren før den faktiske anmodning. Formålet med preflight-requesten er at afgøre, om serveren er villig til at acceptere den faktiske anmodning. Serveren svarer på preflight-requesten med information om de tilladte metoder, headere og andre restriktioner.
Preflight-requests udløses, når anmodningen på tværs af oprindelser opfylder enhver af følgende betingelser:
- Anmodningsmetoden er ikke
GET,HEADellerPOST. - Anmodningen inkluderer brugerdefinerede headere (dvs. andre headere end dem, der automatisk tilføjes af browseren).
Content-Type-headeren er sat til noget andet endapplication/x-www-form-urlencoded,multipart/form-dataellertext/plain.- Anmodningen bruger
ReadableStream-objekter i body.
For eksempel vil en PUT-anmodning med en Content-Type på application/json udløse en preflight-request, fordi den bruger en anden metode end de tilladte og en potentielt ikke-tilladt indholdstype.
Hvorfor Preflight-requests?
Preflight-requests er afgørende for sikkerheden, fordi de giver serveren mulighed for at afvise potentielt skadelige anmodninger på tværs af oprindelser, før de udføres. Uden preflight-requests kunne et ondsindet websted potentielt sende vilkårlige anmodninger til en server uden serverens udtrykkelige samtykke. En preflight-request giver serveren mulighed for at validere, at anmodningen er acceptabel, og forhindrer potentielt skadelige operationer.
Håndtering af Preflight-requests på serversiden
Korrekt håndtering af preflight-requests er afgørende for at sikre, at din webapplikation fungerer korrekt og sikkert. Serveren skal svare på OPTIONS-anmodningen med de passende CORS-headere for at indikere, om den faktiske anmodning er tilladt.
Her er en oversigt over de vigtigste CORS-headere, der bruges i preflight-svar:
Access-Control-Allow-Origin: Denne header specificerer den eller de oprindelser, der har tilladelse til at få adgang til ressourcen. Den kan sættes til en specifik oprindelse (f.eks.https://www.example.com) eller til*for at tillade alle oprindelser. Brug af*frarådes dog generelt af sikkerhedsmæssige årsager, især hvis serveren håndterer følsomme data.Access-Control-Allow-Methods: Denne header specificerer de HTTP-metoder, der er tilladt for anmodningen på tværs af oprindelser (f.eks.GET,POST,PUT,DELETE).Access-Control-Allow-Headers: Denne header specificerer listen over ikke-standard HTTP-headere, der er tilladt i den faktiske anmodning. Dette er nødvendigt, hvis klienten sender brugerdefinerede headere, såsomX-Custom-HeaderellerAuthorization.Access-Control-Allow-Credentials: Denne header angiver, om den faktiske anmodning kan inkludere legitimationsoplysninger, såsom cookies eller autorisationsheadere. Den skal sættes tiltrue, hvis koden på klientsiden sender legitimationsoplysninger, og serveren skal acceptere dem. Bemærk: Når denne header er sat til `true`, kan `Access-Control-Allow-Origin` *ikke* sættes til `*`. Du skal specificere oprindelsen.Access-Control-Max-Age: Denne header specificerer den maksimale tid (i sekunder), som browseren kan cache preflight-svaret. Dette kan hjælpe med at forbedre ydeevnen ved at reducere antallet af sendte preflight-requests.
Eksempel: Håndtering af Preflight-requests i Node.js med Express
Her er et eksempel på, hvordan man håndterer preflight-requests i en Node.js-applikation ved hjælp af Express-frameworket:
const express = require('express');
const cors = require('cors');
const app = express();
// Aktiver CORS for alle oprindelser (kun til udviklingsformål!)
// I produktion skal du specificere tilladte oprindelser for bedre sikkerhed.
app.use(cors()); //eller app.use(cors({origin: 'https://www.example.com'}));
// Rute til håndtering af OPTIONS-requests (preflight)
app.options('/data', cors()); // Aktiver CORS for en enkelt rute. Eller specificer oprindelse: cors({origin: 'https://www.example.com'})
// Rute til håndtering af GET-requests
app.get('/data', (req, res) => {
res.json({ message: 'This is cross-origin data!' });
});
// Rute til at håndtere en preflight og en post-request
app.options('/resource', cors()); // aktiver pre-flight request for DELETE-request
app.delete('/resource', cors(), (req, res, next) => {
res.send('delete resource')
})
const port = 3000;
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
I dette eksempel bruger vi cors-middleware til at håndtere CORS-anmodninger. For mere granulær kontrol kan CORS aktiveres på en per-rute basis. Bemærk: I produktion anbefales det kraftigt at specificere de tilladte oprindelser ved hjælp af origin-indstillingen i stedet for at tillade alle oprindelser. At tillade alle oprindelser med * kan udsætte din applikation for sikkerhedssårbarheder.
Eksempel: Håndtering af Preflight-requests i Python med Flask
Her er et eksempel på, hvordan man håndterer preflight-requests i en Python-applikation ved hjælp af Flask-frameworket og flask_cors-udvidelsen:
from flask import Flask, jsonify
from flask_cors import CORS, cross_origin
app = Flask(__name__)
CORS(app) # Aktiver CORS for alle ruter
@app.route('/data')
@cross_origin()
def get_data():
data = {"message": "This is cross-origin data!"}
return jsonify(data)
if __name__ == '__main__':
app.run(debug=True)
Dette er den enkleste brug. Som før kan oprindelserne begrænses. Se flask-cors-dokumentationen for detaljer.
Eksempel: Håndtering af Preflight-requests i Java med Spring Boot
Her er et eksempel på, hvordan man håndterer preflight-requests i en Java-applikation ved hjælp af Spring Boot:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@SpringBootApplication
public class CorsApplication {
public static void main(String[] args) {
SpringApplication.run(CorsApplication.class, args);
}
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/data").allowedOrigins("http://localhost:8080");
}
};
}
}
Og den tilsvarende controller:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DataController {
@GetMapping("/data")
public String getData() {
return "This is cross-origin data!";
}
}
Almindelige CORS-problemer og løsninger
På trods af dens vigtighed kan CORS ofte være en kilde til frustration for udviklere. Her er nogle almindelige CORS-problemer og deres løsninger:
-
Fejl: "No 'Access-Control-Allow-Origin' header is present on the requested resource."
Denne fejl indikerer, at serveren ikke returnerer
Access-Control-Allow-Origin-headeren i sit svar. For at rette dette skal du sikre, at serveren er konfigureret til at inkludere headeren, og at den er sat til den korrekte oprindelse eller til*(hvis det er passende).Løsning: Konfigurer serveren til at inkludere `Access-Control-Allow-Origin`-headeren i sit svar, og sæt den til oprindelsen af det anmodende websted eller til `*` for at tillade alle oprindelser (brug med forsigtighed).
-
Fejl: "Response to preflight request doesn't pass access control check: Request header field X-Custom-Header is not allowed by Access-Control-Allow-Headers in preflight response."
Denne fejl indikerer, at serveren ikke tillader den brugerdefinerede header (
X-Custom-Headeri dette eksempel) i anmodningen på tværs af oprindelser. For at rette dette skal du sikre, at serveren inkluderer headeren iAccess-Control-Allow-Headers-headeren i preflight-svaret.Løsning: Tilføj den brugerdefinerede header (f.eks. `X-Custom-Header`) til `Access-Control-Allow-Headers`-headeren i serverens preflight-svar.
-
Fejl: "Credentials flag is 'true', but the 'Access-Control-Allow-Origin' header is '*'."
Når
Access-Control-Allow-Credentials-headeren er sat tiltrue, skalAccess-Control-Allow-Origin-headeren sættes til en specifik oprindelse, ikke*. Dette skyldes, at det ville være en sikkerhedsrisiko at tillade legitimationsoplysninger fra alle oprindelser.Løsning: Når du bruger legitimationsoplysninger, skal du sætte `Access-Control-Allow-Origin` til en specifik oprindelse i stedet for `*`.
-
Preflight-request sendes ikke.
Dobbelttjek, at din Javascript-kode inkluderer egenskaben `credentials: 'include'`. Tjek også, at din server tillader `Access-Control-Allow-Credentials: true`.
-
Modstridende konfigurationer mellem server og klient.
Kontroller omhyggeligt din server-side CORS-konfiguration sammen med klient-side indstillingerne. Uoverensstemmelser (f.eks. serveren tillader kun GET-requests, men klienten sender POST) vil forårsage CORS-fejl.
CORS og bedste praksis for sikkerhed
Selvom CORS tillader kontrolleret adgang på tværs af oprindelser, er det vigtigt at følge bedste praksis for sikkerhed for at forhindre sårbarheder:
- Undgå at bruge
*iAccess-Control-Allow-Origin-headeren i produktion. Dette giver alle oprindelser adgang til dine ressourcer, hvilket kan være en sikkerhedsrisiko. Specificer i stedet de nøjagtige oprindelser, der er tilladt. - Overvej omhyggeligt, hvilke metoder og headere du vil tillade. Tillad kun de metoder og headere, der er strengt nødvendige for, at din applikation kan fungere korrekt.
- Implementer korrekte autentificerings- og autorisationsmekanismer. CORS er ikke en erstatning for autentificering og autorisation. Sørg for, at din API er beskyttet af passende sikkerhedsforanstaltninger.
- Valider og rens al brugerinput. Dette hjælper med at forhindre cross-site scripting (XSS) angreb og andre sårbarheder.
- Hold din server-side CORS-konfiguration opdateret. Gennemgå og opdater jævnligt din CORS-konfiguration for at sikre, at den stemmer overens med din applikations sikkerhedskrav.
CORS i forskellige udviklingsmiljøer
CORS-problemer kan manifestere sig forskelligt på tværs af forskellige udviklingsmiljøer og teknologier. Her er et kig på, hvordan man håndterer CORS i et par almindelige scenarier:
Lokale udviklingsmiljøer
Under lokal udvikling kan CORS-problemer være særligt irriterende. Browsere blokerer ofte anmodninger fra din lokale udviklingsserver (f.eks. localhost:3000) til en fjern-API. Flere teknikker kan lette denne smerte:
- Browserudvidelser: Udvidelser som "Allow CORS: Access-Control-Allow-Origin" kan midlertidigt deaktivere CORS-restriktioner til testformål. Brug dog *aldrig* disse i produktion.
- Proxy-servere: Konfigurer en proxy-server, der videresender anmodninger fra din lokale udviklingsserver til fjern-API'en. Dette gør effektivt anmodningerne til "same-origin" fra browserens perspektiv. Værktøjer som
http-proxy-middleware(for Node.js) er nyttige til dette. - Konfigurer serverens CORS: Selv under udvikling er det bedste praksis at konfigurere din API-server til eksplicit at tillade anmodninger fra din lokale udviklingsoprindelse (f.eks.
http://localhost:3000). Dette simulerer en virkelig CORS-konfiguration og hjælper dig med at fange problemer tidligt.
Serverless-miljøer (f.eks. AWS Lambda, Google Cloud Functions)
Serverless-funktioner kræver ofte omhyggelig CORS-konfiguration. Mange serverless-platforme tilbyder indbygget CORS-support, men det er afgørende at konfigurere det korrekt:
- Platformspecifikke indstillinger: Brug platformens indbyggede CORS-konfigurationsmuligheder. AWS Lambda giver dig for eksempel mulighed for at specificere tilladte oprindelser, metoder og headere direkte i API Gateway-indstillingerne.
- Middleware/Biblioteker: For større fleksibilitet kan du bruge middleware eller biblioteker til at håndtere CORS i din serverless-funktionskode. Dette ligner de tilgange, der bruges i traditionelle servermiljøer (f.eks. ved at bruge
cors-pakken i Node.js Lambda-funktioner). - Overvej
OPTIONS-metoden: Sørg for, at din serverless-funktion håndtererOPTIONS-anmodninger korrekt. Dette indebærer ofte at oprette en separat rute, der returnerer de passende CORS-headere.
Mobilapp-udvikling (f.eks. React Native, Flutter)
CORS er mindre af en direkte bekymring for native mobilapps (Android, iOS), da de typisk ikke håndhæver same-origin policy på samme måde som webbrowsere. CORS kan dog stadig være relevant, hvis din mobilapp bruger en web view til at vise webindhold, eller hvis du bruger frameworks som React Native eller Flutter, der udnytter JavaScript:
- Web Views: Hvis din mobilapp bruger en web view til at vise webindhold, gælder de samme CORS-regler som i en webbrowser. Konfigurer din server til at tillade anmodninger fra oprindelsen af webindholdet.
- React Native/Flutter: Disse frameworks bruger JavaScript til at foretage API-anmodninger. Selvom det native miljø måske ikke håndhæver CORS direkte, kan de underliggende HTTP-klienter (f.eks.
fetch) stadig udvise CORS-lignende adfærd i visse situationer. - Native HTTP-klienter: Når du foretager API-anmodninger direkte fra native kode (f.eks. ved hjælp af OkHttp på Android eller URLSession på iOS), er CORS generelt ikke en faktor. Du skal dog stadig overveje bedste praksis for sikkerhed, såsom korrekt autentificering og autorisation.
Globale overvejelser for CORS-konfiguration
Når du konfigurerer CORS for en globalt tilgængelig applikation, er det afgørende at overveje faktorer som:
- Datasuverænitet: Regler i nogle regioner kræver, at data forbliver inden for regionen. CORS kan være involveret, når der tilgås ressourcer på tværs af grænser, hvilket potentielt kan komme i konflikt med love om dataopbevaring.
- Regionale sikkerhedspolitikker: Forskellige lande kan have forskellige cybersikkerhedsregler og retningslinjer, der påvirker, hvordan CORS skal implementeres og sikres.
- Content Delivery Networks (CDN'er): Sørg for, at dit CDN er korrekt konfigureret til at sende de nødvendige CORS-headere igennem. Forkert konfigurerede CDN'er kan fjerne CORS-headere, hvilket fører til uventede fejl.
- Load Balancers og Proxies: Verificer, at eventuelle load balancers eller reverse proxies i din infrastruktur håndterer preflight-requests korrekt og sender CORS-headere igennem.
- Flersproget support: Overvej, hvordan CORS interagerer med din applikations internationaliserings- (i18n) og lokaliseringsstrategier (l10n). Sørg for, at CORS-politikker er konsistente på tværs af forskellige sprogversioner af din applikation.
Test og fejlfinding af CORS
Effektiv test og fejlfinding af CORS er afgørende. Her er nogle teknikker:
- Browserens udviklerværktøjer: Browserens udviklerkonsol er dit første stop. Fanen "Network" viser preflight-requests og svarene, hvilket afslører, om CORS-headere er til stede og korrekt konfigureret.
- `curl`-kommandolinjeværktøj: Brug `curl -v -X OPTIONS
` til manuelt at sende preflight-requests og inspicere serverens svarheadere. - Online CORS-tjekkere: Talrige onlineværktøjer kan hjælpe med at validere din CORS-konfiguration. Søg bare efter "CORS checker".
- Enheds- og integrationstests: Skriv automatiserede tests for at verificere, at din CORS-konfiguration fungerer som forventet. Disse tests bør dække både vellykkede anmodninger på tværs af oprindelser og scenarier, hvor CORS skal blokere adgang.
- Logning og overvågning: Implementer logning for at spore CORS-relaterede hændelser, såsom preflight-requests og blokerede anmodninger. Overvåg dine logs for mistænkelig aktivitet eller konfigurationsfejl.
Konklusion
Cross-Origin Resource Sharing (CORS) er en vital sikkerhedsmekanisme, der muliggør kontrolleret adgang på tværs af oprindelser til webressourcer. Forståelse af, hvordan CORS fungerer, især preflight-requests, er afgørende for at bygge sikre og pålidelige webapplikationer. Ved at følge de bedste praksis, der er beskrevet i denne guide, kan du effektivt håndtere CORS-problemer og beskytte din applikation mod potentielle sårbarheder. Husk altid at prioritere sikkerhed og omhyggeligt overveje konsekvenserne af din CORS-konfiguration.
Efterhånden som webudvikling udvikler sig, vil CORS fortsat være et kritisk aspekt af websikkerhed. At holde sig informeret om de seneste bedste praksis og teknikker for CORS er afgørende for at bygge sikre og globalt tilgængelige webapplikationer.